#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <sys/select.h>
#include "Log.hpp"
#include "Socket.hpp"
#include <cerrno>
#include <functional>

using namespace LogMudule;

#define NUM sizeof(fd_set) * 8

const int gdefaultfd = -1;
using handle_t = std::function<std::string (const std:: string )>;

class SelectServer
{

public:
    SelectServer(int port,handle_t handle)
        : _port(port),
          _sock(std::make_shared<TcpSocket>(gdefaultfd)),
          _handle(handle)
    {
    }

    // 初始化
    void Init()
    {
        // 初始化套接字
        _sock->BuildTcpSocketMethod(_port);

        // 初始化辅组数组
        _fd_v.resize(NUM);
        for (int i = 0; i < _fd_v.size(); ++i)
        {
            _fd_v[i] = nullptr;
        }

        // 将监听套接字加入辅组数组
        _fd_v[0] = _sock;
    }

    void Start()
    {
        while (true)
        {
            // 设置fd_set + 最大fd
            int maxfd = gdefaultfd;
            fd_set rset;
            FD_ZERO(&rset);
            for (int i = 0; i < _fd_v.size(); ++i)
            {
                if (_fd_v[i] != nullptr)
                {
                    LOG(LogLevel::DEBUG) <<"_fd_v[i]: "<< _fd_v[i]->Fd();
                    FD_SET(_fd_v[i]->Fd(), &rset);

                    if (maxfd < _fd_v[i]->Fd())
                    {
                        maxfd = _fd_v[i]->Fd();
                    }
                }
            }

            // 设置超时时间
            struct timeval timeout;
            timeout.tv_sec = 10;
            timeout.tv_usec = 0;

            // 开始等待
            int n = select(maxfd+1, &rset, nullptr, nullptr, &timeout);
            if (n > 0) // 有就绪的文件描述符
            {
                LOG(LogLevel::DEBUG) << "有就绪的文件描述符" << " 剩余时间 " << timeout.tv_sec << ":" << timeout.tv_usec;
                DisposeFd(rset);
                //对就绪的文件描述符处理
            }
            else if (n == 0) // 没有就绪的文件描述符
            {
                LOG(LogLevel::DEBUG) << "时间到了，没有就绪的文件描述符";
                continue;
            }
            else
            {
                LOG(LogLevel::ERROR) << "select error :" << errno;
                return;
            }
        }
    }

    void DisposeFd(fd_set &rset)
    {
        for (int i = 0; i < _fd_v.size(); ++i)
        {
            if (_fd_v[i] == nullptr)
            {
                continue;
            }

            // 是监听文件描述符
            if (_fd_v[i]->Fd() == _sock->Fd())
            {
                // 有新连接到来
                if (FD_ISSET(_fd_v[i]->Fd(), &rset))
                {
                    // 处理连接
                    Accept();
                }
            }
            else if (FD_ISSET(_fd_v[i]->Fd(), &rset)) // 通信文件描述符
            {
                // 处理信息
                RS(_fd_v[i]);
            }
        }
    }

    void Accept()
    {
        InetAddr client;
        std::shared_ptr<Socket> sk = _sock->Accepter(&client);

        // 添加套接字进辅组数组
        int index = -1;
        for (int i = 0; i < _fd_v.size(); ++i)
        {
            if (_fd_v[i] == nullptr)
            {
                index = i;
                break;
            }
        }

        // 能够管理的fd满了
        if (index == -1)
        {
            sk->Close();
            return;
        }

        _fd_v[index] =  sk;
        //_select_arry[index] = sk->Fd();
    }

    void RS(std::shared_ptr<Socket> & fd)
    {
        std::string out;
        int n = fd->Recv(&out);
        if (n > 0) // 读到数据
        {
            LOG(LogLevel::DEBUG) << "buffer: " << out;

            std::string res = _handle(out);

            LOG(LogLevel::DEBUG) << "准备发送： " << fd->Fd();
            int n = fd->Send(res);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "send err...";
            }
            LOG(LogLevel::DEBUG) << "send succeed...";
        }
        else if (n == 0) // 对端关闭
        {
            // 关闭fd
           fd->Close();

            // 从辅组数组中移出
            for (int i = 0; i <_fd_v.size() ; ++i)
            {
                if (_fd_v[i] != nullptr && _fd_v[i]->Fd() == fd->Fd())
                {
                    //std::shared_ptr<Socket>置空 -1
                    _fd_v[i] = nullptr;
                    break;
                }
            }

            LOG(LogLevel::DEBUG) << "对端退出";
        }
        else
        {
            LOG(LogLevel::ERROR) << "read err...";
            return;
        }
    }

    ~SelectServer()
    {
        for (int i = 0; i < _fd_v.size(); ++i)
        {
            if (_fd_v[i] != nullptr)
            {
                _fd_v[i]->Close();
            }
        }
    }

private:
    uint16_t _port;                // 端口号
    std::shared_ptr<Socket> _sock; // socket
    std::vector<std::shared_ptr<Socket>> _fd_v; //读写套接字

   // int _select_arry[NUM]; // 辅组数组
    handle_t _handle;
};